package com.haoqizhe.kernel.activemq.properties;

import org.apache.activemq.*;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Primary;

/**
 * @author haoqizhe.li on 2017/7/31.
 */
@ConfigurationProperties(prefix="kernel.activemq")
@Primary
public class ActivemqProperties {

    /**
     * 连接客户端ID
     */
    private String clientId;
    /**
     * 发送消息前缀
     */
    private String destinationPrefix;

    /**
     * broker使用内存模式时，连接的broker url
     */
    private String brokerUrl;
    /**
     * activemq 连接工厂 session缓存数
     */
    private int sessionCacheSize;

    /**
     * Enables or disables the default setting of whether or not consumers have their messages dispatched synchronously or asynchronously by the broker.
     * For non-durable topics for example we typically dispatch synchronously by default to minimize context switches which boost performance.
     * However sometimes its better to go slower to ensure that a single blocked consumer socket does not block delivery to other consumers.
     */
    private boolean dispatchAsync;
    /**
     * If this flag is not set then a separate thread is not used for dispatching messages for each Session in the Connection.
     * However, a separate thread is always used if there is more than one session, or the session isn't in auto acknowledge or duplicates ok mode.
     * By default this value is set to true and session dispatch happens asynchronously.
     */
    private boolean alwaysSessionAsync;
    /**
     * Should a JMS message be copied to a new JMS Message object as part of the send() method in JMS.
     * This is enabled by default to be compliant with the JMS specification.
     * You can disable it if you do not mutate JMS messages after they are sent for a performance boost
     */
    private boolean copyMessageOnSend;
    /**
     * Sets whether or not timestamps on messages should be disabled or not.
     * If you disable them it adds a small performance boost.
     */
    private boolean disableTimeStampsByDefault;

    /**
     * When an object is set on an ObjectMessage, the JMS spec requires the object to be serialized by that set method.
     * Enabling this flag causes the object to not get serialized.
     * The object may subsequently get serialized if the message needs to be sent over a socket or stored to disk.
     */
    private Boolean objectMessageSerializationDefered;
    /**
     * If this flag is set then an larger prefetch limit is used - only applicable for durable topic subscribers.
     */
    private boolean optimizedMessageDispatch;

    /**
     *  Forces the use of Async Sends which adds a massive performance boost;
     *  but means that the send() method will return immediately whether the message has been sent or not which could lead to message loss.
     *  是否异步发送，异步发送将大大提升发送者性能，同时意味着消息可能会丢失。
     */
    private boolean useAsyncSend;
    /**
     * Enables the use of compression of the message bodies
     * 是否开启压缩消息体
     */
    private boolean useCompression;

    /**
     * Sets whether or not retroactive consumers are enabled.
     * Retroactive consumers allow non-durable topic subscribers to receive old messages that were published before the non-durable subscriber started.
     * 是否开启追溯消息，作用于topic消息，非持久化消息亦能在消费者启动后被消费。
     */
    private Boolean useRetroactiveConsumer;

    private boolean watchTopicAdvisories;

    /**
     * Sets the timeout before a close is considered complete.
     * Normally a close() on a connection waits for confirmation from the broker;
     * this allows that operation to timeout to save the client hanging if there is no broker
     */
    private int closeTimeout;

    private Boolean optimizeAcknowledge;

    private Boolean statsEnabled;
    /**
     * Set true if always require messages to be sync sent
     * 是否总是同步发送
     */
    private boolean alwaysSyncSend;
    /**
     * 生产消息窗口尺寸，用来约束在异步发送时producer端允许积压的(尚未ACK)的消息的尺寸，且只对异步发送有意义。
     # 每次发送消息之后，都将会导致memoryUsage尺寸增加(+message.size)，当broker返回producerAck时，memoryUsage尺寸减少(producerAck.size，此size表示先前发送消息的大小)
     # 如果达到了producerWindowSize上限，即使是异步调用也会被阻塞，防止不停向broker发送消息。
     */
    private int producerWindowSize;
    /**
     * 发送消息超时时间
     */
    private int sendTimeout;

    private int connectResponseTimeout;
    /**
     * 是否异步发送ack
     */
    private boolean sendAcksAsync;

    private int auditDepth;

    private int auditMaximumProducerNumber;

    private boolean checkForDuplicates;

    private boolean messagePrioritySupported;

    /**
     * when true, submit individual transacted acks immediately rather than with transaction completion.
     * This allows the acks to represent delivery status which can be persisted on rollback Used in conjunction with org.apache.
     * activemq.store.kahadb.KahaDBPersistenceAdapter#setRewriteOnRedelivery(boolean) true
     */
    private boolean transactedIndividualAck;
    /**
     * When true a MessageConsumer will not stop Message delivery before re-delivering Messages from a rolled back transaction.
     * This implies that message order will not be preserved and also will result in the TransactedIndividualAck option to be enabled.
     */
    private boolean nonBlockingRedelivery;

    private int maxThreadPoolSize;
    /**
     * Enables/disables whether or not Message properties and MapMessage entries support Nested Structures of Map and List objects
     */
    private boolean nestedMapAndListEnabled;
    /**
     *
     */
    private long consumerFailoverRedeliveryWaitPeriod;

    /**
     * uses the connection id as the resource identity for XAResource.
     * isSameRM ensuring join will only occur on a single connection
     */
    private boolean rmIdFromConnectionId;
    /**
     * Controls whether message expiration checking is done in each MessageConsumer prior to dispatching a message.
     * Disabling this check can lead to consumption of expired messages
     *
     * 启用消息过期检查,默认true，禁用消息将永不过期
     */
    private boolean consumerExpiryCheckEnabled;
    /**
     * Enables or disables whether or not queue consumers should be exclusive or not for example to preserve ordering when not using Message Groups
     */
    private Boolean exclusiveConsumer;

    /**
     * Sets the amount of time between scheduled sends of any outstanding Message Acks for consumers that have been configured with optimizeAcknowledge enabled.
     */
    private long optimizedAckScheduledAckInterval;

    private Boolean useDedicatedTaskRunner;

    /**
     * Enables the timeout from a connection creation to when a warning is generated if the connection is not properly started via Connection.start() and a message is received by a consumer.
     * It is a very common gotcha to forget to start the connection so this option makes the default case to create a warning if the user forgets.
     * To disable the warning just set the value to < 0 (say -1).
     */
    private long warnAboutUnstartedConnectionTimeout;

    public ActivemqProperties(){
        this.clientId = "";
        this.destinationPrefix = "";
        this.brokerUrl = "vm://localhost?broker.persistent=false";
        this.sessionCacheSize = 100;

        /**默认修改为异步发送，并设置消息窗口大小位1024000=100M**/
        this.alwaysSyncSend = false;
        this.useAsyncSend = true;
        this.producerWindowSize = 1024000;
        /**默认修改为异步发送，并设置消息窗口大小位1024000=100M**/

        this.dispatchAsync = true;
        /**
         * 优化consumer线程，一个connection只会有一个session实例
         */
        this.alwaysSessionAsync = false;

        this.optimizedAckScheduledAckInterval = 0;
        this.warnAboutUnstartedConnectionTimeout = 500L;

        this.disableTimeStampsByDefault = false;
        this.optimizedMessageDispatch = true;
        this.copyMessageOnSend = true;
        this.closeTimeout = 15000;
        this.nestedMapAndListEnabled = true;
        this.watchTopicAdvisories = true;
        this.sendTimeout = 0;
        this.connectResponseTimeout = 0;
        this.sendAcksAsync = true;
        this.auditDepth = 2048;
        this.auditMaximumProducerNumber = 64;
        this.consumerFailoverRedeliveryWaitPeriod = 0L;
        this.checkForDuplicates = true;
        this.messagePrioritySupported = false;
        this.transactedIndividualAck = false;
        this.nonBlockingRedelivery = false;
        this.maxThreadPoolSize = ActiveMQConnection.DEFAULT_THREAD_POOL_SIZE;
        this.rmIdFromConnectionId = false;
        this.consumerExpiryCheckEnabled = true;

    }


    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public String getDestinationPrefix() {
        return destinationPrefix;
    }

    public void setDestinationPrefix(String destinationPrefix) {
        this.destinationPrefix = destinationPrefix;
    }

    public String getBrokerUrl() {
        return brokerUrl;
    }

    public void setBrokerUrl(String brokerUrl) {
        this.brokerUrl = brokerUrl;
    }

    public int getSessionCacheSize() {
        return sessionCacheSize;
    }

    public void setSessionCacheSize(int sessionCacheSize) {
        this.sessionCacheSize = sessionCacheSize;
    }


    public boolean isDispatchAsync() {
        return dispatchAsync;
    }

    public void setDispatchAsync(boolean dispatchAsync) {
        this.dispatchAsync = dispatchAsync;
    }

    public boolean isCopyMessageOnSend() {
        return copyMessageOnSend;
    }

    public void setCopyMessageOnSend(boolean copyMessageOnSend) {
        this.copyMessageOnSend = copyMessageOnSend;
    }

    public boolean isDisableTimeStampsByDefault() {
        return disableTimeStampsByDefault;
    }

    public void setDisableTimeStampsByDefault(boolean disableTimeStampsByDefault) {
        this.disableTimeStampsByDefault = disableTimeStampsByDefault;
    }

    public Boolean isObjectMessageSerializationDefered() {
        return objectMessageSerializationDefered;
    }

    public void setObjectMessageSerializationDefered(Boolean objectMessageSerializationDefered) {
        this.objectMessageSerializationDefered = objectMessageSerializationDefered;
    }

    public boolean isOptimizedMessageDispatch() {
        return optimizedMessageDispatch;
    }

    public void setOptimizedMessageDispatch(boolean optimizedMessageDispatch) {
        this.optimizedMessageDispatch = optimizedMessageDispatch;
    }

    public boolean isUseAsyncSend() {
        return useAsyncSend;
    }

    public void setUseAsyncSend(boolean useAsyncSend) {
        this.useAsyncSend = useAsyncSend;
    }

    public boolean isUseCompression() {
        return useCompression;
    }

    public void setUseCompression(boolean useCompression) {
        this.useCompression = useCompression;
    }

    public Boolean isUseRetroactiveConsumer() {
        return useRetroactiveConsumer;
    }

    public void setUseRetroactiveConsumer(Boolean useRetroactiveConsumer) {
        this.useRetroactiveConsumer = useRetroactiveConsumer;
    }

    public boolean isWatchTopicAdvisories() {
        return watchTopicAdvisories;
    }

    public void setWatchTopicAdvisories(boolean watchTopicAdvisories) {
        this.watchTopicAdvisories = watchTopicAdvisories;
    }

    public int getCloseTimeout() {
        return closeTimeout;
    }

    public void setCloseTimeout(int closeTimeout) {
        this.closeTimeout = closeTimeout;
    }

    public boolean isAlwaysSessionAsync() {
        return alwaysSessionAsync;
    }

    public void setAlwaysSessionAsync(boolean alwaysSessionAsync) {
        this.alwaysSessionAsync = alwaysSessionAsync;
    }

    public Boolean isOptimizeAcknowledge() {
        return optimizeAcknowledge;
    }

    public void setOptimizeAcknowledge(Boolean optimizeAcknowledge) {
        this.optimizeAcknowledge = optimizeAcknowledge;
    }

    public Boolean isStatsEnabled() {
        return statsEnabled;
    }

    public void setStatsEnabled(Boolean statsEnabled) {
        this.statsEnabled = statsEnabled;
    }

    public boolean isAlwaysSyncSend() {
        return alwaysSyncSend;
    }

    public void setAlwaysSyncSend(boolean alwaysSyncSend) {
        this.alwaysSyncSend = alwaysSyncSend;
    }

    public int getProducerWindowSize() {
        return producerWindowSize;
    }

    public void setProducerWindowSize(int producerWindowSize) {
        this.producerWindowSize = producerWindowSize;
    }

    public int getSendTimeout() {
        return sendTimeout;
    }

    public void setSendTimeout(int sendTimeout) {
        this.sendTimeout = sendTimeout;
    }

    public int getConnectResponseTimeout() {
        return connectResponseTimeout;
    }

    public void setConnectResponseTimeout(int connectResponseTimeout) {
        this.connectResponseTimeout = connectResponseTimeout;
    }

    public boolean isSendAcksAsync() {
        return sendAcksAsync;
    }

    public void setSendAcksAsync(boolean sendAcksAsync) {
        this.sendAcksAsync = sendAcksAsync;
    }

    public int getAuditDepth() {
        return auditDepth;
    }

    public void setAuditDepth(int auditDepth) {
        this.auditDepth = auditDepth;
    }

    public int getAuditMaximumProducerNumber() {
        return auditMaximumProducerNumber;
    }

    public void setAuditMaximumProducerNumber(int auditMaximumProducerNumber) {
        this.auditMaximumProducerNumber = auditMaximumProducerNumber;
    }

    public boolean isCheckForDuplicates() {
        return checkForDuplicates;
    }

    public void setCheckForDuplicates(boolean checkForDuplicates) {
        this.checkForDuplicates = checkForDuplicates;
    }

    public boolean isMessagePrioritySupported() {
        return messagePrioritySupported;
    }

    public void setMessagePrioritySupported(boolean messagePrioritySupported) {
        this.messagePrioritySupported = messagePrioritySupported;
    }

    public boolean isTransactedIndividualAck() {
        return transactedIndividualAck;
    }

    public void setTransactedIndividualAck(boolean transactedIndividualAck) {
        this.transactedIndividualAck = transactedIndividualAck;
    }

    public boolean isNonBlockingRedelivery() {
        return nonBlockingRedelivery;
    }

    public void setNonBlockingRedelivery(boolean nonBlockingRedelivery) {
        this.nonBlockingRedelivery = nonBlockingRedelivery;
    }

    public int getMaxThreadPoolSize() {
        return maxThreadPoolSize;
    }

    public void setMaxThreadPoolSize(int maxThreadPoolSize) {
        this.maxThreadPoolSize = maxThreadPoolSize;
    }

    public boolean isNestedMapAndListEnabled() {
        return nestedMapAndListEnabled;
    }

    public void setNestedMapAndListEnabled(boolean nestedMapAndListEnabled) {
        this.nestedMapAndListEnabled = nestedMapAndListEnabled;
    }

    public long getConsumerFailoverRedeliveryWaitPeriod() {
        return consumerFailoverRedeliveryWaitPeriod;
    }

    public void setConsumerFailoverRedeliveryWaitPeriod(long consumerFailoverRedeliveryWaitPeriod) {
        this.consumerFailoverRedeliveryWaitPeriod = consumerFailoverRedeliveryWaitPeriod;
    }

    public boolean isRmIdFromConnectionId() {
        return rmIdFromConnectionId;
    }

    public void setRmIdFromConnectionId(boolean rmIdFromConnectionId) {
        this.rmIdFromConnectionId = rmIdFromConnectionId;
    }

    public boolean isConsumerExpiryCheckEnabled() {
        return consumerExpiryCheckEnabled;
    }

    public void setConsumerExpiryCheckEnabled(boolean consumerExpiryCheckEnabled) {
        this.consumerExpiryCheckEnabled = consumerExpiryCheckEnabled;
    }

    public Boolean isExclusiveConsumer() {
        return exclusiveConsumer;
    }

    public void setExclusiveConsumer(Boolean exclusiveConsumer) {
        this.exclusiveConsumer = exclusiveConsumer;
    }

    public long getOptimizedAckScheduledAckInterval() {
        return optimizedAckScheduledAckInterval;
    }

    public void setOptimizedAckScheduledAckInterval(long optimizedAckScheduledAckInterval) {
        this.optimizedAckScheduledAckInterval = optimizedAckScheduledAckInterval;
    }

    public Boolean isUseDedicatedTaskRunner() {
        return useDedicatedTaskRunner;
    }

    public void setUseDedicatedTaskRunner(Boolean useDedicatedTaskRunner) {
        this.useDedicatedTaskRunner = useDedicatedTaskRunner;
    }

    public long getWarnAboutUnstartedConnectionTimeout() {
        return warnAboutUnstartedConnectionTimeout;
    }

    public void setWarnAboutUnstartedConnectionTimeout(long warnAboutUnstartedConnectionTimeout) {
        this.warnAboutUnstartedConnectionTimeout = warnAboutUnstartedConnectionTimeout;
    }
}
